
package sci.tool;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.Executors;

import android.os.Handler;
import sci.tool.ThreadTool.ThreadPram;


/** SocketClient.java: 对Socket进行简单接口封装，便于使用。
 * 
 * 用法：
 * client = new SocketClient(print, ipString, port);	// 创建客户端Socket操作对象
 * client.start();										// 连接服务器
 * client.Send(data);									// 发送信息
 * client.disconnect();									// 断开连接
 * 
 * ----- 2019-6-18 下午5:36:25 scimence */
public class SocketClient
{
	public String ipString = "127.0.0.1";   // 服务器端ip
	public int port = 37280;                // 服务器端口
	
	public Socket socket;
	public SocketCallBack call;				// 数据接收回调方法
	
	public SocketClient(SocketCallBack print, String ipString, int port)
	{
		this.call = print;
		if (ipString != null) this.ipString = ipString;
		if (port >= 0) this.port = port;
	}
	
	/** 创建Socket并连接, 延时执行 */
	public void start(long delayMillis)
	{
		new Handler().postDelayed(new Runnable()
		{
			@Override
			public void run()
			{
				start();
			}
		}, delayMillis);
	}
	
	/** 创建Socket并连接 */
	public void start()
	{
		if (socket != null && socket.isConnected()) return;
		
		Executors.newCachedThreadPool().execute(new Runnable()
		{
			@Override
			public void run()
			{
				try
				{
					if (socket == null)
					{
						InetAddress ip = InetAddress.getByName(ipString);
						socket = new Socket(ip, port);
						
						if (call != null) call.Print("服务器已连接 -> " + ip + ":" + port);
					}
				}
				catch (Exception ex)
				{
					if (call != null) call.Print("连接服务器失败 " + ex.toString()); // 连接失败
				}
				
				// Socket接收数据
				try
				{
					if (socket != null)
					{
						InputStream inputStream = socket.getInputStream();
						
						// 1024 * 1024 * 3 = 3145728
//						byte[] buffer = new byte[3145728];		// 3M缓存
						byte[] buffer = new byte[204800];		// 200KB缓存
						int len = -1;
						while (true)
						{
							if(socket.isConnected() && (len = inputStream.read(buffer)) != -1)
							{
								String data = new String(buffer, 0, len);
								
								if(ReceiveFilter(data)) continue;
								
								// 通过回调接口将获取到的数据推送出去
								if (call != null)
								{
									if(groupName.equals("msg")) data = "接收信息 -> " + data;
									call.Print(data);
								}
							}
						}
						
					}
				}
				catch (Exception ex)
				{
					if (call != null) call.Print("接收socket信息失败" + ex.toString()); // 连接失败
					socket = null;
				}
			}
		});
	}
	
	/** 发送信息 */
	public void Send(String data0)
	{
		if(data0.length() > 8192) data0 = "[dataStart]" + data0 + "[dataEnd]";   // 当数据超出最大缓存发送值时，进行格式封装
		final String data = data0;
		
		ThreadTool.RunInCachedThread(new ThreadPram()
		{
			@Override
			public void Function()
			{
				try
				{
					if(socket != null && socket.isConnected())
					{
						byte[] bytes = data.getBytes();
						OutputStream outputStream = socket.getOutputStream();
						outputStream.write(bytes);
						
						if(groupName.equals("msg"))	// 仅msg组消息输出回显，其它分组直接发送
						{
							if(data.contains("[cmd]")) return; // 操作命令不回显
							if (call != null) call.Print("发送信息 -> " + data);
						}
					}
					else
					{
						if (call != null) call.Print("未连接服务器！清先连接后，再发送。");
					}
				}
				catch (Exception ex)
				{
					if (call != null) call.Print("发送socket信息失败！");
					if (call != null) call.Print(ex.toString());
				}
			}
		});
		
	}
	
	/** 返回当前Socket连接状态 */
	public boolean isConnected()
	{
		if(socket != null && socket.isConnected()) return true;
		else return false;
	}
	
	/** 断开Socket */
	public void disconnect()
	{
		try
		{
			if (socket != null && socket.isConnected())
			{
				socket.close();
				socket = null;
				
				if (call != null) call.Print("服务器已断开！ ");
			}
		}
		catch (Exception ex)
		{
			if (call != null) call.Print("断开socket失败!" + "\r\n" + ex.toString());
		}
	}
	
	// ----------------
	// 附加命令参数处理逻辑
	
	private String groupName = "msg";
	
	/** 对接收到的参数命令进行处理  */
	private boolean ReceiveFilter(String data)
	{
		if(data.equals("[groupName]")) Send("[groupName]"+ groupName);	// 返回当前SocketClient的名称
		else return false;
		
		return true;
	}
	
	/** 创建Socket并连接，指定Socket分组类型 */
	public SocketClient(SocketCallBack print, String ipString, int port, String groupName)
	{
		this.groupName = groupName;
		this.call = print;
		if (ipString != null) this.ipString = ipString;
		if (port >= 0) this.port = port;
	}
}
